/*
 * Copyright (c) 2012 Universidad Antonio de Nebrija.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0.html
 * 
 * Contributors:
 *    Universidad Antonio de Nebrija - initial API, implementation and documentation
 */
package com.nebrija.riif.model;

import java.util.Set;

/**
 * Represents an assert RIIF element
 * @author asanchep
 *
 */
public class AssertValidation implements RIIFElement {

	//TODO: Build a model for assertions affecting more than one property
	/** Comparison operator */
	private AssertOperator operator = AssertOperator.TRUE;
	/** The object representing the target element holding the property */
	private RIIFProperties target;
	/** the name of the target property */
	private String targetProperty;
	/** the string with the expression of the value to be compared to */
	private String compareValue;
	/** the calculated value for the comparison */
	private Object calcCompareValue;
	
	/** the result of the assertion */
	private boolean assertionResult=false;
	/** indicates if the assertionResult is valid or not calculated yet */
	private boolean calculated=false;
	
	public AssertValidation(RIIFProperties element, String property, AssertOperator op, String expression){
		if(op!=null){
			operator=op;
		}
		compareValue=expression;
		target=element;
		targetProperty= property;
	}


	@Override
	public String getName() {
		return "ASSERT_" + target.getName() + "_" + targetProperty;
	}

	public AssertOperator getOperator() {
		return operator;
	}

	public void setOperator(AssertOperator operator) {
		if(operator==null){
			return;
		}
		this.operator = operator;
	}

	public RIIFProperties getTarget() {
		return target;
	}

	public void setTarget(RIIFProperties target) {
		this.target = target;
	}

	public String getTargetProperty() {
		return targetProperty;
	}

	public void setTargetProperty(String targetProperty) {
		this.targetProperty = targetProperty;
	}

	public String getCompareValue() {
		return compareValue;
	}

	public void setCompareValue(String compareValue) {
		this.compareValue = compareValue;
	}

	@Override
	public boolean equals(Object arg0) {
		if(!(arg0 instanceof AssertValidation)){
			return false;
		}
		AssertValidation compare = (AssertValidation)arg0;
		if(!operator.equals(compare.getOperator())){
			return false;
		}
		if(!targetProperty.equals(compare.getTargetProperty())){
			return false;
		}
		if(!compareValue.equals(compare.getCompareValue())){
			return false;
		}	
		if(!target.getName().equals(compare.getTarget().getName())){
			return false;
		}			
		return true;
	}

	
	@Override
	public String toString() {
		StringBuffer str = new StringBuffer (getName());
		str.append(":=>");
		str.append(target.getName()).append("[").append(targetProperty).append("]")
				.append(operator).append (" ").append(compareValue);
		if(isCalculated()){
			str.append(":=>").append("RESULT IS ").append(this.assertionResult);
		}
		return str.toString();		
	}


	@Override
	public void resolve(RIIFElement container) {
		// Calculate the value to be compared to
		setCalcCompareValue(Util.resolveFormula(compareValue, (Component) container));
	}

	@Override
	public void clear(RIIFElement container) {
		// Remove the calculation and clear the assertion result
		setCalcCompareValue(null);
		this.setCalculated(false);
		this.assertionResult=false;
	}
	
	public Object getCalcCompareValue() {
		return calcCompareValue;
	}


	public void setCalcCompareValue(Object calcCompareValue) {
		this.calcCompareValue = calcCompareValue;
	}
	
	/**
	 * Calculates the assertion result
	 * @return
	 */
	public boolean getAssertionResult(){
		Object cvalue = target.getProperty(targetProperty+ RIIFProperties.CALCULATED_SUFFIX);
		if(cvalue==null || (cvalue instanceof String)  
				|| calcCompareValue==null || (calcCompareValue instanceof String)){
			return false;
		}
		
		Double propertyValue = Util.convertToDouble(cvalue);
		Double compareToValue = Util.convertToDouble(this.calcCompareValue);
		
		setCalculated(true);
		
		switch (operator){
			case TRUE: assertionResult=true;
						break;
			case FALSE: assertionResult=false;
						break;
			case EQUAL: assertionResult= ((propertyValue-compareToValue)==0);
						break;
			case DISTINCT: assertionResult= ((propertyValue-compareToValue)!=0);
						   break;	
			case GREATER: assertionResult= ((propertyValue-compareToValue)>0);
						   break;
			case GREATER_EQUAL: assertionResult= ((propertyValue-compareToValue)>=0);
							break;
			case LESS: assertionResult= ((propertyValue-compareToValue)<0);
							break;
			case LESS_EQUAL: assertionResult= ((propertyValue-compareToValue)<=0);
							break;
		}
		
		return assertionResult;
	}


	public boolean isCalculated() {
		return calculated;
	}


	public void setCalculated(boolean calculated) {
		this.calculated = calculated;
	}


	@Override
	public int getChildCount() {
		return 0;
	}


	@Override
	public RIIFElement getElement(String name) {
		return null;
	}


	@Override
	public Set<String> getElementNames() {
		return null;
	}

}
